// 角色道具

package m

import (
	"fmt"

	"github.com/globalsign/mgo/bson"
	log "github.com/sirupsen/logrus"

	"GameServer/Common/data"
	"GameServer/Game/cache"
	"GameServer/Game/dbmodule"
	"GameServer/Game/errors"
)

// 玩家的英雄集合
type Heros struct {
	BaseM
	Uid       bson.ObjectId    `bson:"_id" json:"_id"`             // 直接是玩家id
	GiveTime  int64            `bson:"giveTime" json:"giveTime"`   // 赠送卡片时间
	SendCount int64            `bson:"sendCount" json:"sendCount"` // 赠送卡片次数
	Heros     map[int64]string `bson:"heros" json:"heros"`         // key:英雄tid，val:英雄表中的_id
}

// 英雄信息
type Hero struct {
	BaseM
	Uid     bson.ObjectId        `bson:"_id" json:"_id"`
	Tid     int64                `bson:"tid" json:"tid"`         // 英雄tid
	Goods   map[int64]*HeroGoods `bson:"goods"`                  // 英雄道具（英雄物品）
	SkillId int64                `bson:"skillId" json:"skillId"` // 英雄技能
}

// 英雄物品
type HeroGoods struct {
	Tid   int64 `bson:"tid" json:"tid"`   // 物品tid
	Num   int64 `bson:"num" json:"num"`   // 物品数量
	Star  int64 `bson:"star" json:"star"` // 物品星星
	IsNew int64 `json:"isNew"`            // 0.旧道具、1.新道具
}

// 没有的英雄装备
type HeroGoodNotOwned struct {
	BaseM
	Uid     bson.ObjectId `bson:"_id" json:"_id"` // 用户id
	GoodTid []int64       `bson:"tid" json:"tid"` // 物品tid
}

// 玩家的英雄：创建
func NewHeros() cache.EntryI {
	return &Heros{Heros: make(map[int64]string)}
}

// 玩家的英雄：保存信息
func (heros *Heros) Save() (err error) {
	err = dbmodule.MgoDB.GameDB.Upsert("heros", bson.M{"_id": heros.Uid}, heros)
	return
}

// 玩家的英雄：加载
func (heros *Heros) Load(key interface{}) (err error) {
	switch key.(type) {
	case string:
		if key.(string) == "" {
			return errors.New("无效的key load, key empty")
		}
		heros.Uid = bson.ObjectIdHex(key.(string))
	case bson.ObjectId:
		heros.Uid = key.(bson.ObjectId)
	default:
		log.WithFields(log.Fields{
			"method": "Heros_Load",
			"data":   key,
		}).Error("无效的key load")
		return errors.New("无效的key load")
	}
	return heros.LoadData()
}

// 玩家的英雄：加载数据
func (heros *Heros) LoadData() (err error) {
	err = dbmodule.MgoDB.GameDB.FindOne("heros", bson.M{"_id": heros.Uid}, nil, &heros)
	if err != nil {
		if err.Error() == "not found" {
			return nil
		}
		return
	}
	if heros.Heros == nil {
		heros.Heros = make(map[int64]string)
	}
	return
}

// 玩家的英雄：更新数据
func (heros *Heros) Update(val *Heros) {
	Cache.Put("heros", heros.Uid.Hex(), val)
	val.UpdateData()
}

// 玩家的英雄：给玩家的英雄添加道具
func (heros *Heros) AddHeroGoods(goodsT data.Good, num int64) (hero *Hero, uprop *UpdateProp) {
	defer heros.Update(heros)
	heroTid := int64(goodsT.Owner) //英雄tid
	goodstid := int64(goodsT.Id)   //道具tid

	uprop = NewUpdateProp()
	heroGoods := &HeroGoods{Tid: goodstid, Num: num, Star: int64(goodsT.Star)}
	uprop.HeroGoodsList = append(uprop.HeroGoodsList, heroGoods)
	// 玩家拥有英雄
	if v, ok := heros.Heros[heroTid]; ok {
		if hero, ok := heros.GetHero(v); ok { // 拥有英雄信息
			// 修改的英雄的装备 需要更新
			defer hero.Update(hero)
			if v1, ok := hero.Goods[goodstid]; ok { // 英雄拥有该道具
				// 增加该道具数量
				v1.Num += num
				return hero, uprop
			}
			// 英雄没有该道具，添加道具
			hero.Goods[goodstid] = heroGoods
			heroGoods.IsNew = 1 //没有该道具，是新道具
			//fmt.Printf("1.新道具%d   isNew = %d \n", goodstid, heroGoods.IsNew)
			uprop.Kvs = append(uprop.Kvs, &BaseKV{Key: data.GlobalEnum.Star, Val: int64(goodsT.Star)})
			return hero, uprop
		}
	}
	// 没有拥有该英雄，给玩家添加英雄
	hero = &Hero{
		Uid:     bson.NewObjectId(),
		Tid:     heroTid,                       // 英雄tid
		Goods:   make(map[int64]*HeroGoods, 0), // 英雄道具（英雄物品）
		SkillId: 0,                             // 英雄技能
	}
	hero.Goods[goodstid] = heroGoods // 英雄添加道具
	heroGoods.IsNew = 1              //没有该道具，是新道具
	//fmt.Printf("2.新道具%d   isNew = %d \n", goodstid, heroGoods.IsNew)
	hero.Update(hero)

	heros.Heros[heroTid] = hero.Uid.Hex()

	uprop.Kvs = append(uprop.Kvs, &BaseKV{Key: data.GlobalEnum.Star, Val: int64(goodsT.Star)})
	return
}

// 玩家的英雄：通过英雄id获取英雄信息
func (heros *Heros) GetHero(uid string) (r *Hero, ok bool) {
	v, ok := Cache.Get("hero", uid)
	if !ok {
		return
	}
	r = v.(*Hero)
	return
}

// 玩家的英雄：通过英雄tid获取英雄信息
func (heros *Heros) GetHeroByTid(tid int64) (r *Hero, ok bool) {
	uid, ok := heros.Heros[tid]
	if !ok {
		return
	}
	r, ok = heros.GetHero(uid)
	return
}

// 玩家的英雄：获取玩家的英雄的道具
func (heros *Heros) GetHeroGoods(heroTid int64) (r map[int64]*HeroGoods, ok bool) {
	heroUid, ok := heros.Heros[heroTid]
	if !ok {
		fmt.Println("没有该英雄 heroTid=", heroTid)
		return
	}
	hero, ok := heros.GetHero(heroUid)
	if !ok {
		fmt.Println("有该英雄 heroTid=", heroTid, "没有该英雄数据", heroUid)
		return
	}
	r = hero.Goods
	return
}

// 玩家的英雄：获取玩家所有英雄信息
func (heros *Heros) GetHeroMap() (r map[int64]*Hero) {
	r = make(map[int64]*Hero)
	for key, item := range heros.Heros {
		if hero, ok := heros.GetHero(item); ok {
			r[key] = hero
		}
	}
	return
}

// 玩家的英雄：获取玩家所有英雄信息
func (heros *Heros) GetHeroList() (r []*Hero) {
	r = make([]*Hero, 0)
	for _, item := range heros.Heros {
		if hero, ok := heros.GetHero(item); ok {
			r = append(r, hero)
		}
	}
	return
}

// 根据物品tid获取到英雄物品信息
func (heros *Heros) GetHeroGoodsByGoodsTid(tid int64) (r *HeroGoods, ok bool) {
	// heroTid, ok := heroall.GetHeroTidByGoodTid(tid)
	tpl, ok := data.Get("Goods", uint64(tid))
	if !ok {
		fmt.Println("没有该英雄")
		return
	}
	tplT := tpl.(data.Good)
	// 通过英雄tid，玩家该英雄的所有道具
	mHgoods, ok := heros.GetHeroGoods(int64(tplT.Owner))
	if !ok {
		return
	}
	r, ok = mHgoods[tid]
	return
}

// 玩家英雄：扣除英雄物品数量，goodTid：物品tid，num：扣除数量
func (heros *Heros) CostHeroGoods(goodTid, num int64) (uProp *UpdateProp, err error) {
	// 数据层，通过物品tid拿到英雄tid
	tpl, ok := data.Get("Goods", uint64(goodTid))
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, fmt.Sprintf("没有该配表Goods，或者没有该道具 %d", goodTid))
		return
	}
	goodT := tpl.(data.Good)
	heroUid, ok := heros.Heros[int64(goodT.Owner)]
	if !ok {
		err = errors.NewErrcode(data.Errcode.NoHero, fmt.Sprintf("玩家没有该英雄 %d", goodT.Owner))
		return
	}
	hero, ok := heros.GetHero(heroUid)
	if !ok {
		err = errors.NewErrcode(data.Errcode.NoHero, fmt.Sprintf("获取英雄信息失败 %d", goodT.Owner))
		return
	}
	g, ok := hero.Goods[goodTid]
	if !ok {
		err = errors.NewErrcode(data.Errcode.NoHeroGoods, fmt.Sprintf("玩家没有该道具 %d", goodTid))
		return
	}
	// 数量不能少于1
	if g.Num-num < 1 {
		err = errors.NewErrcode(data.Errcode.NoHeroGoods, fmt.Sprintf("玩家道具不够扣去 %d %d", g.Num, num))
		return
	}
	g.Num -= num
	hero.Update(hero)

	uProp = NewUpdateProp()
	heroGoods := &HeroGoods{Tid: goodTid, Num: -num, Star: int64(goodT.Star)}
	uProp.HeroGoodsList = append(uProp.HeroGoodsList, heroGoods)
	return
}

// 玩家英雄列表信息
func (u *User) Heros() (r *Heros) {
	v1, _ := Cache.Get("heros", u.Uid.Hex())
	r = v1.(*Heros)
	return
}

// 在没有的装备中，删除拥有的tid
func (u *User) RemoveNotGoodTid(tid int64) {
	hgno, _ := u.GetHeroGoodNotOwned()

	var iflag int = -1
	for idx, item := range hgno.GoodTid {
		if item == tid {
			iflag = idx
			break
		}
	}
	if iflag >= 0 {
		hgno.GoodTid = append(hgno.GoodTid[:iflag], hgno.GoodTid[iflag+1:]...)
	}
	hgno.Update(hgno)
}

// 给该用户的英雄添加道具
// func (u *User) AddHeroGoods(goodsT data.Good, num int64) (uprop *UpdateProp, err error) {
// 	if num == 0 {
// 		err = errors.NewErrcode(data.Errcode.ServerErr, fmt.Sprintf("AddHeroGoods goods 数量为0goods tid:%d", goodsT.Id))
// 		return
// 	}
// 	// 移除已拥有的装备
// 	u.RemoveNotGoodTid(int64(goodsT.Id))

// 	hero, uprop := u.Heros().AddHeroGoods(goodsT, num)
// 	u.StarHero = u.Heros().SumHeroStar() //统计玩家英雄的星星数量
// 	u.Update(u)
// 	// 当英雄拥有所有道具，就能激活，并且拥有技能。没有技能，SkillId是0
// 	if hero.SkillId != 0 {
// 		return
// 	}
// 	// Owner：英雄的tid，英雄的道具满了，就能拥有英雄和英雄技能
// 	if !hero.CheckFullGoods(int64(goodsT.Owner)) {
// 		fmt.Println("英雄道具没满")
// 		return uprop, nil
// 	}

// 	// 从配置表中，获取英雄信息
// 	herosTpl, ok := data.Get("Heros", goodsT.Owner)
// 	if !ok {
// 		err = errors.NewErrcode(data.Errcode.ConfigNotFound, fmt.Sprintf("没有找到英雄配置:heros id:%d", goodsT.Owner))
// 		return
// 	}

// 	heroT := herosTpl.(data.Hero)

// 	// 从配置表中获取英雄技能信息，根据技能id
// 	heroSkillTpl, ok := data.Get("HeroSkills", heroT.Skill)
// 	if !ok {
// 		err = errors.NewErrcode(data.Errcode.ConfigNotFound, fmt.Sprintf("没有找到英雄技能配置:heros skill id:%d", heroT.Skill))
// 		return
// 	}

// 	skillT := heroSkillTpl.(data.HeroSkill)
// 	hero.AddSkill(int64(skillT.Id)) // 英雄添加技能

// 	uprop.HeroUprops = append(uprop.HeroUprops, &HeroUprop{Tid: hero.Tid, SkillId: hero.SkillId})

// 	switch int64(skillT.Type) {
// 	case data.HeroSkillTypeEnum.PetGet: // 获得宠物
// 		fmt.Println("获得宠物")
// 		kv, pet, upropPetInfo, err := u.GetUserPet().AddPet(utils.Int64(skillT.Effect))
// 		if err != nil {
// 			return uprop, err
// 		}
// 		if pet != nil {
// 			uprop.Pets = append(uprop.Pets, pet)
// 		}
// 		if upropPetInfo != nil {
// 			uprop.Petinfo = upropPetInfo
// 		}
// 		if kv != nil {
// 			uprop.Kvs = append(uprop.Kvs, kv)
// 		}
// 		// 重新计算宠物星星
// 		u.StarPet = u.GetUserPet().SumPetStar()
// 		u.Update(u)
// 	case data.HeroSkillTypeEnum.PetPlus: // 宠物进阶
// 		fmt.Println("宠物进阶")
// 		switch skillT.Effect.(type) {
// 		case map[string]interface{}:
// 			mEffect := skillT.Effect.(map[string]interface{})
// 			key := mEffect["key"]     // 宠物tid
// 			val := mEffect["value"]   //进阶值
// 			if key == 0 && val == 0 { // 无效值
// 				return nil, nil
// 			}
// 			// 宠物进阶
// 			uprop1, pet, err := u.GetUserPet().AddPetStep(utils.Int64(key), utils.Int64(val))
// 			if err != nil {
// 				return uprop, err
// 			}
// 			if pet != nil {
// 				uprop.Pets = append(uprop.Pets, pet)
// 			}
// 			if uprop1 != nil {
// 				uprop.Merge(uprop1)
// 			}
// 			// 重新计算宠物星星
// 			u.StarPet = u.GetUserPet().SumPetStar()
// 			u.Update(u)
// 		default:
// 			fmt.Println("无效 宠物进阶 类型 effect :", goodsT.Effect)
// 		}
// 	case data.HeroSkillTypeEnum.GridCost: // 挖矿相关辅助技能
// 		fmt.Println("挖矿相关辅助技能")
// 		switch int64(skillT.ExtType) {
// 		case data.HeroSkillExtTypeEnum.HandleGoldRate: // 拾起金币，增加金币
// 			u.HandleGoldRate += utils.Int64(skillT.Effect)
// 		case data.HeroSkillExtTypeEnum.TheftGoldRate: // 被偷盗，减少被偷金币
// 			u.TheftGoldRate += utils.Int64(skillT.Effect)
// 		case data.HeroSkillExtTypeEnum.FireGridRate: // 挖焦土，减少消耗金币
// 			u.FireGridRate += utils.Int64(skillT.Effect)
// 			uprop.Kvs = append(uprop.Kvs, &BaseKV{Key: data.GlobalEnum.FireGridRate, Val: utils.Int64(skillT.Effect)})
// 		default:
// 			fmt.Println("无效的辅助类型：", skillT.ExtType)
// 		}
// 	default:
// 		fmt.Println("无效的英雄技能的类型：", skillT.Type)
// 	}
// 	return
// }

// 英雄：创建
func NewHero() cache.EntryI {
	return &Hero{Goods: make(map[int64]*HeroGoods)}
}

// 英雄：保存信息
func (hero *Hero) Save() (err error) {
	err = dbmodule.MgoDB.GameDB.Upsert("hero", bson.M{"_id": hero.Uid}, hero)
	return
}

// 英雄：加载
func (hero *Hero) Load(key interface{}) (err error) {
	switch key.(type) {
	case string:
		if key.(string) == "" {
			return errors.New("无效的key load, key empty")
		}
		hero.Uid = bson.ObjectIdHex(key.(string))
	case bson.ObjectId:
		hero.Uid = key.(bson.ObjectId)
	default:
		log.WithFields(log.Fields{
			"method": "Hero_Load",
			"data":   key,
		}).Error("无效的key load")
		return errors.New("无效的key load")
	}
	return hero.LoadData()
}

// 英雄：加载数据
func (hero *Hero) LoadData() (err error) {
	err = dbmodule.MgoDB.GameDB.FindOne("hero", bson.M{"_id": hero.Uid}, nil, &hero)
	if err != nil {
		if err.Error() == "not found" {
			return nil
		}
		return
	}
	if hero.Goods == nil {
		hero.Goods = make(map[int64]*HeroGoods)
	}
	return
}

// 英雄：更新数据
func (hero *Hero) Update(val *Hero) {
	Cache.Put("hero", hero.Uid.Hex(), val)
	val.UpdateData()
}

// 英雄：扣除道具
func (hero *Hero) CostGood(tid, num int64) (err error) {
	g, ok := hero.Goods[tid]
	if !ok {
		err = errors.NewErrcode(data.Errcode.NoHeroGoods, fmt.Sprintf("玩家没有该道具 %d", tid))
		return
	}
	if g.Num-num < 1 {
		err = errors.NewErrcode(data.Errcode.NoHeroGoods, fmt.Sprintf("玩家道具不够扣去 %d %d", g.Num, num))
		return
	}
	g.Num -= num
	hero.Update(hero)
	return
}

// 英雄：添加道具
func (hero *Hero) AddGood(g *HeroGoods) (ok bool) {
	defer hero.Update(hero)
	tg, ok := hero.Goods[g.Tid]
	if ok {
		tg.Num += g.Num
		return
	}
	hero.Goods[g.Tid] = &HeroGoods{
		Tid:  g.Tid,
		Num:  g.Num,
		Star: g.Star,
	}
	return true
}

// 英雄：添加技能
func (hero *Hero) AddSkill(skillId int64) (ok bool) {
	defer hero.Update(hero)
	hero.SkillId = skillId
	return true
}

// 英雄：统计装备星星总数
func (hero *Hero) GetStarNum() (r int64) {
	r = 0
	for _, item := range hero.Goods {
		r += item.Star
	}
	return
}

// 英雄：检查英雄是否集满物品
func (hero *Hero) CheckFullGoods(heroTid int64) (ok bool) {
	// 获取该英雄的所有装备
	// list, ok := heroall.GetGoodsTidByHeroTid(heroTid)
	tplList, ok := data.Filters("Goods", func(val interface{}) bool {
		good := val.(data.Good)
		return int64(good.Owner) == heroTid
	})
	if !ok {
		return false
	}
	// 判断该玩家的英雄集满道具
	for _, item := range tplList {
		itemT := item.(data.Good)
		// 玩家英雄是否拥有该道具
		if _, ok := hero.Goods[int64(itemT.Id)]; !ok {
			return false
		}
	}
	return true
}

// 没有的装备：创建
func NewHeroGoodNotOwned() cache.EntryI {
	return &HeroGoodNotOwned{GoodTid: make([]int64, 0)}
}

// 没有的装备：保存信息
func (h *HeroGoodNotOwned) Save() (err error) {
	err = dbmodule.MgoDB.GameDB.Upsert("HeroGoodNotOwned", bson.M{"_id": h.Uid}, h)
	return
}

// 没有的装备：加载
func (h *HeroGoodNotOwned) Load(key interface{}) (err error) {
	switch key.(type) {
	case string:
		if key.(string) == "" {
			return errors.New("无效的key load, key empty")
		}
		h.Uid = bson.ObjectIdHex(key.(string))
	case bson.ObjectId:
		h.Uid = key.(bson.ObjectId)
	default:
		log.WithFields(log.Fields{
			"method": "HeroGoodNotOwned_Load",
			"data":   key,
		}).Error("无效的key load")
		return errors.New("无效的key load")
	}
	return h.LoadData()
}

// 没有的装备：加载数据
func (h *HeroGoodNotOwned) LoadData() (err error) {
	err = dbmodule.MgoDB.GameDB.FindOne("HeroGoodNotOwned", bson.M{"_id": h.Uid}, nil, &h)
	if err != nil {
		if err.Error() == "not found" {
			return nil
		}
		return
	}
	if h.GoodTid == nil {
		h.GoodTid = make([]int64, 0)
	}
	return
}

// 没有的装备：更新数据
func (h *HeroGoodNotOwned) Update(val *HeroGoodNotOwned) {
	Cache.Put("HeroGoodNotOwned", val.Uid.Hex(), val)
	val.UpdateData()
}

// 没有的装备：获取
func (u *User) GetHeroGoodNotOwned() (r *HeroGoodNotOwned, ok bool) {
	val, ok := Cache.Get("HeroGoodNotOwned", u.Uid.Hex())
	if !ok {
		return
	}
	if val == nil {
		ok = false
		return
	}
	r = val.(*HeroGoodNotOwned)
	return
}
